/*
 * @(#)XfsimLimit.java        2003/01/01
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */


package xfuzzy.xfsim.model;


/**
 * Valores l�mite del proceso de simulaci�n
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfsimLimit {
	
	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * L�mite superior del n�mero de iteraciones
	 */
	private int nLimit;
	
	/**
	 * L�mite superior del tiempo de simulaci�n
	 */
	private double tLimit;
	
	/**
	 * Lista de l�mites inferiores de los valores de entrada al sistema difuso
	 */
	private double[] iLowLimit;
	
	/**
	 * Lista de l�mites superiores de los valores de entrada al sistema difuso
	 */
	private double[] iHighLimit;

	/**
	 * Lista de l�mites inferiores de los valores de salida del sistema difuso
	 */
	private double[] oLowLimit;
	
	/**
	 * Lista de l�mites superiores de los valores de salida del sistema difuso
	 */
	private double[] oHighLimit;
	
	/**
	 * Marcador del l�mite superior del n�mero de iteraciones
	 */
	private boolean nFlag;
	
	/**
	 * Marcador del l�mite superior del tiempo de simulaci�n
	 */
	private boolean tFlag;
	
	/**
	 * Marcadores de los l�mites inferiores de los valores de entrada al sistema difuso
	 */
	private boolean[] iLowFlag;
	
	/**
	 * Marcadores de los l�mites superiores de los valores de entrada al sistema difuso
	 */
	private boolean[] iHighFlag;

	/**
	 * Marcadores de los l�mites inferiores de los valores de salida del sistema difuso
	 */
	private boolean[] oLowFlag;
	
	/**
	 * Marcadores de los l�mites superiores de los valores de salida del sistema difuso
	 */
	private boolean[] oHighFlag;

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfsimLimit(int inputs, int outputs) {
		this.iHighLimit = new double[inputs];
		this.iLowLimit = new double[inputs];
		this.oHighLimit = new double[outputs];
		this.oLowLimit = new double[outputs];
		
		this.iHighFlag = new boolean[inputs];
		this.iLowFlag = new boolean[inputs];
		this.oHighFlag = new boolean[outputs];
		this.oLowFlag = new boolean[outputs];
	}
	
	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Verifica si se ha asignado el l�mite superior del n�mero de iteraciones
	 */
	public boolean isSetNLimit() {
		return nFlag;
	}
	
	/**
	 * Obtiene el l�mite superior del n�mero de iteraciones
	 */
	public int getNLimit() {
		return nLimit;
	}
	
	/**
	 * Verifica si se ha asignado el l�mite superior del tiempo
	 */
	public boolean isSetTLimit() {
		return tFlag;
	}
	
	/**
	 * Obtiene el l�mite superior del tiempo
	 * @return
	 */
	public double getTLimit() {
		return tLimit;
	}

	/**
	 * Verifica si se ha asignado el l�mite inferior de una variable de entrada del
	 * sistema difuso
	 * @param index
	 * @return
	 */
	public boolean isSetInputLowLimit(int index) {
		if(index >= iLowFlag.length) return false;
		return iLowFlag[index];
	}
	
	/**
	 * Obtiene el l�mite inferior de una variable de entrada del sistema difuso
	 * @param index
	 * @return
	 */
	public double getInputLowLimit(int index) {
		if(index >= iLowLimit.length) return 0;
		return iLowLimit[index];
	}

	/**
	 * Verifica si se ha asignado el l�mite superior de una variable de entrada del
	 * sistema difuso
	 * @param index
	 * @return
	 */
	public boolean isSetInputHighLimit(int index) {
		if(index >= iHighFlag.length) return false;
		return iHighFlag[index];
	}
	

	/**
	 * Obtiene el l�mite superior de una variable de entrada del sistema difuso
	 * @param index
	 * @return
	 */
	public double getInputHighLimit(int index) {
		if(index >= iHighLimit.length) return 0;
		return iHighLimit[index];
	}

	/**
	 * Verifica si se ha asignado el l�mite inferior de una variable de salida del
	 * sistema difuso
	 * @param index
	 * @return
	 */
	public boolean isSetOutputLowLimit(int index) {
		if(index >= oLowFlag.length) return false;
		return oLowFlag[index];
	}
	

	/**
	 * Obtiene el l�mite inferior de una variable de salida del sistema difuso
	 * @param index
	 * @return
	 */
	public double getOutputLowLimit(int index) {
		if(index >= oLowLimit.length) return 0;
		return oLowLimit[index];
	}

	/**
	 * Verifica si se ha asignado el l�mite superior de una variable de salida del
	 * sistema difuso
	 * @param index
	 * @return
	 */
	public boolean isSetOutputHighLimit(int index) {
		if(index >= oHighFlag.length) return false;
		return oHighFlag[index];
	}	

	/**
	 * Obtiene el l�mite superior de una variable de salida del sistema difuso
	 * @param index
	 * @return
	 */
	public double getOutputHighLimit(int index) {
		if(index >= oHighLimit.length) return 0;
		return oHighLimit[index];
	}
	
	/**
	 * Asigna el l�mite superior del n�mero de iteraciones
	 * @param limit
	 */
	public void setNLimit(int limit) {
		this.nLimit = limit;
		this.nFlag = true;
	}
	
	/**
	 * Asigna el l�mite superior del tiempo de simulaci�n
	 * @param limit
	 */
	public void setTLimit(double limit) {
		this.tLimit = limit;
		this.tFlag = true;
	}
	
	/**
	 * Asigna el l�mite inferior de una entrada del sistema difuso
	 * @param index
	 * @param limit
	 */
	public void setInputLowLimit(int index, double limit) {
		if(index >= iLowLimit.length) {
			double[] auxLimit = new double[index+1];
			System.arraycopy(iLowLimit, 0, auxLimit, 0, iLowLimit.length);
			iLowLimit = auxLimit;
			
			boolean[] auxFlag = new boolean[index+1];
			System.arraycopy(iLowFlag, 0, auxFlag, 0, iLowFlag.length);
			iLowFlag = auxFlag;	
		}
		iLowLimit[index] = limit;
		iLowFlag[index] = true;
	}

	/**
	 * Asigna el l�mite superior de una entrada del sistema difuso
	 * @param index
	 * @param limit
	 */
	public void setInputHighLimit(int index, double limit) {
		if(index >= iHighLimit.length) {
			double[] auxLimit = new double[index+1];
			System.arraycopy(iHighLimit, 0, auxLimit, 0, iHighLimit.length);
			iHighLimit = auxLimit;
			
			boolean[] auxFlag = new boolean[index+1];
			System.arraycopy(iHighFlag, 0, auxFlag, 0, iHighFlag.length);
			iHighFlag = auxFlag;
		}
		iHighLimit[index] = limit;
		iHighFlag[index] = true;
	}

	/**
	 * Asigna el l�mite inferior de una salida del sistema difuso
	 * @param index
	 * @param limit
	 */
	public void setOutputLowLimit(int index, double limit) {
		if(index >= oLowLimit.length) {
			double[] auxLimit = new double[index+1];
			System.arraycopy(oLowLimit, 0, auxLimit, 0, oLowLimit.length);
			oLowLimit = auxLimit;
			
			boolean[] auxFlag = new boolean[index+1];
			System.arraycopy(oLowFlag, 0, auxFlag, 0, oLowFlag.length);
			oLowFlag = auxFlag;	
		}
		oLowLimit[index] = limit;
		oLowFlag[index] = true;
	}

	/**
	 * Asigna el l�mite superior de una entrada del sistema difuso
	 * @param index
	 * @param limit
	 */
	public void setOutputHighLimit(int index, double limit) {
		if(index >= oHighLimit.length) {
			double[] auxLimit = new double[index+1];
			System.arraycopy(oHighLimit, 0, auxLimit, 0, oHighLimit.length);
			oHighLimit = auxLimit;
			
			boolean[] auxFlag = new boolean[index+1];
			System.arraycopy(oHighFlag, 0, auxFlag, 0, oHighFlag.length);
			oHighFlag = auxFlag;
		}
		oHighLimit[index] = limit;
		oHighFlag[index] = true;
	}
	
	/**
	 * Verifica que alg�n l�mite se haya asignado
	 */
	public boolean isConfigured() {
		if(nFlag) return true;
		if(tFlag) return true;
		for(int i=0; i<iLowFlag.length; i++)  if(iLowFlag[i]) return true;
		for(int i=0; i<iHighFlag.length; i++) if(iHighFlag[i]) return true;
		for(int i=0; i<oLowFlag.length; i++)  if(oLowFlag[i]) return true;
		for(int i=0; i<oHighFlag.length; i++) if(oHighFlag[i]) return true;
		return false;
	}
	
	/**
	 * Elimina todos los l�mites
	 */
	public void clearLimits() {
		nLimit = 0; nFlag = false;
		tLimit = 0; tFlag = false;
		for(int i=0; i<iLowLimit.length; i++) { iLowLimit[i] = 0; iLowFlag[i] = false; }
		for(int i=0; i<iHighLimit.length; i++) { iHighLimit[i] = 0; iHighFlag[i] = false; }
		for(int i=0; i<oLowLimit.length; i++) { oLowLimit[i] = 0; oLowFlag[i] = false; }
		for(int i=0; i<oHighLimit.length; i++) { oHighLimit[i] = 0; oHighFlag[i] = false; }
	}
	
	/**
	 * Verifica que los l�mites no se hayan alcanzado
	 */
	public boolean test(XfsimStatus status) {
		if(status.getStatus() == XfsimStatus.FINISHED) return false;
		
		int iter = status.getIteration();
		double time = status.getTime();
		double[] fzst = status.getFuzzyInputs();
		double[] ptst = status.getFuzzyOutputs();
		
		if(nFlag && iter >= nLimit) return false;
		if(tFlag && time >= tLimit) return false;
		for(int i=0; i<fzst.length && i<iLowFlag.length; i++) {
			if(iLowFlag[i] && fzst[i] <= iLowLimit[i]) return false;
			if(iHighFlag[i] && fzst[i] >= iHighLimit[i]) return false;
		}
		for(int i=0; i<ptst.length && i<oLowFlag.length; i++) {
			if(oLowFlag[i] && ptst[i] <= oLowLimit[i]) return false;
			if(oHighFlag[i] && ptst[i] >= oHighLimit[i]) return false;
		}
		return true;
	}
	
	/**
	 * Descripci�n a mostrar en la ventana
	 */
	public String toString() {
		if(isConfigured()) return "configured";
		else return "unconfigured";
	}
	
	/**
	 * Descripci�n a mostrar en el fichero de configuraci�n
	 */
	public String toXML() {
		String eol = System.getProperty("line.separator", "\n");
		String code = "";
		code += "\t\t<limits>"+eol;
		if(nFlag) code += "\t\t\t<n_limit value=\""+nLimit+"\"></n_limit>"+eol;
		if(tFlag) code += "\t\t\t<t_limit value=\""+tLimit+"\"></t_limit>"+eol;
		for(int i=0; i<oLowFlag.length; i++) { 
			code += "\t\t\t<o_low_limit index=\""+i+"\" value=\""+oLowLimit[i]+"\"></o_low_limit>"+eol;
		}
		for(int i=0; i<oHighFlag.length; i++) { 
			code += "\t\t\t<o_high_limit index=\""+i+"\" value=\""+oHighLimit[i]+"\"></o_high_limit>"+eol;
		}
		for(int i=0; i<iLowFlag.length; i++) { 
			code += "\t\t\t<i_low_limit index=\""+i+"\" value=\""+iLowLimit[i]+"\"></i_low_limit>"+eol;
		}
		for(int i=0; i<iHighFlag.length; i++) { 
			code += "\t\t\t<i_high_limit index=\""+i+"\" value=\""+iHighLimit[i]+"\"></i_high_limit>"+eol;
		}
		code += "\t\t</limits>"+eol;
		return code;
	}
}

